% cm_allocate.m
% *** 已修改: 支持多种分配策略 ***
function [manager, offset] = cm_allocate(manager, size_needed, buf_id, allocation_strategy, buf_id_to_free_step, current_buf_free_step)
    offset = -1;
    best_block_idx = -1;
    
    % --- 根据策略选择最佳空闲块 ---
    switch allocation_strategy
        case 'BestFit'
            min_suitable_size = inf;
            for i = 1:length(manager.free_blocks)
                if manager.free_blocks(i).size >= size_needed && manager.free_blocks(i).size < min_suitable_size
                    min_suitable_size = manager.free_blocks(i).size;
                    best_block_idx = i;
                end
            end

        case 'LowAddress'
            min_address = inf;
            for i = 1:length(manager.free_blocks)
                if manager.free_blocks(i).size >= size_needed
                    if manager.free_blocks(i).start < min_address
                        min_address = manager.free_blocks(i).start;
                        best_block_idx = i;
                    end
                end
            end
            
        case 'LifetimeAware'
            best_score = inf; % 得分越小越好
            
            suitable_indices = [];
            for i = 1:length(manager.free_blocks)
                if manager.free_blocks(i).size >= size_needed
                    suitable_indices = [suitable_indices, i];
                end
            end

            if ~isempty(suitable_indices) && ~isempty(manager.allocated_blocks)
                [~, sort_idx] = sort([manager.allocated_blocks.start]);
                sorted_alloc_blocks = manager.allocated_blocks(sort_idx);

                for i = 1:length(suitable_indices)
                    idx = suitable_indices(i);
                    fb = manager.free_blocks(idx);
                    
                    pred_neighbor_freetime = current_buf_free_step;
                    succ_neighbor_freetime = current_buf_free_step;
                    
                    % 查找前驱邻居
                    for j = length(sorted_alloc_blocks):-1:1
                        if sorted_alloc_blocks(j).start + sorted_alloc_blocks(j).size == fb.start
                            if isKey(buf_id_to_free_step, sorted_alloc_blocks(j).buf_id)
                                pred_neighbor_freetime = buf_id_to_free_step(sorted_alloc_blocks(j).buf_id);
                            end
                            break;
                        end
                    end
                    
                    % 查找后继邻居
                    for j = 1:length(sorted_alloc_blocks)
                        if sorted_alloc_blocks(j).start == fb.start + fb.size
                             if isKey(buf_id_to_free_step, sorted_alloc_blocks(j).buf_id)
                                succ_neighbor_freetime = buf_id_to_free_step(sorted_alloc_blocks(j).buf_id);
                            end
                            break;
                        end
                    end
                    
                    score = abs(current_buf_free_step - pred_neighbor_freetime) + abs(current_buf_free_step - succ_neighbor_freetime);
                    
                    if score < best_score
                        best_score = score;
                        best_block_idx = idx;
                    end
                end
            elseif ~isempty(suitable_indices) % 如果没有已分配的块，则退化为BestFit
                 min_suitable_size = inf;
                 for i = 1:length(suitable_indices)
                     idx = suitable_indices(i);
                     if manager.free_blocks(idx).size < min_suitable_size
                         min_suitable_size = manager.free_blocks(idx).size;
                         best_block_idx = idx;
                     end
                 end
            end
    end
    
    % --- 若未找到合适的块，则返回 ---
    if best_block_idx == -1, return; end
    
    % --- 所有策略共用的更新逻辑 ---
    best_block = manager.free_blocks(best_block_idx);
    offset = best_block.start;
    new_alloc_block = struct('start', offset, 'size', size_needed, 'buf_id', buf_id);
    manager.allocated_blocks = [manager.allocated_blocks; new_alloc_block];
    
    % 更新 free_blocks
    if best_block.size > size_needed
        manager.free_blocks(best_block_idx).start = best_block.start + size_needed;
        manager.free_blocks(best_block_idx).size = best_block.size - size_needed;
    else
        manager.free_blocks(best_block_idx) = [];
    end
    
    % 保持 allocated_blocks 有序
    if ~isempty(manager.allocated_blocks)
        [~, sort_idx] = sort([manager.allocated_blocks.start]);
        manager.allocated_blocks = manager.allocated_blocks(sort_idx);
    end
end